package org.opens.lambda.future;

import com.google.common.collect.Lists;
import org.junit.Test;

import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

public class CompletableFutureAndStream {

    private ExecutorService executorService = Executors.newFixedThreadPool(5);

    /**
     * 功能: 测试CompletableFuture的回调机制.
     * 备注:
     * - junit不会等待线程结束, 所以需要将该方法放在main函数中执行或者使当前线程join.
     */
    @Test
    public void test2() throws ExecutionException, InterruptedException {
        CompletableFuture<Double> completableFuture = new CompletableFuture<>();
        new Thread(() -> {
            Double aDouble = get();
            completableFuture.complete(aDouble);
        }).start();
        System.out.println("start");
        completableFuture.whenComplete((v, t) -> {
            //如果存在结果就打印结果, 也就是说, 这里写异步任务执行完毕后的逻辑代码
            Optional.ofNullable(v).ifPresent(System.out::println);
            //如果存在异常则打印异常
            Optional.ofNullable(t).ifPresent(Throwable::printStackTrace);
        });
        System.out.println("end");
        Thread.currentThread().join();
    }

    /**
     * 功能: 测试使用stream搭配CompletableFuture处理批量数据.
     * 输出:
     * ```
     * [9.0, 65.0, 217.0, 513.0, 1001.0]
     * ```
     * 结论:
     * - 可以进行处理, 但是应用场景不多.
     */
    @Test
    public void batchOfStream() {
        List<Double> arrs = Lists.newArrayList(1D, 2D, 3D, 4D, 5D);
        List<Double> collect = arrs.stream().map(x -> CompletableFuture.supplyAsync(() -> x * 2, executorService))
                .map(z -> z.thenApply(v -> Math.pow(v, 3)))
                // 该过程可以无线叠加
                .map(z -> z.thenApply(v1 -> v1 + 1))
                .map(CompletableFuture::join)
                .collect(Collectors.toList());
        System.out.println(collect);
    }

    /**
     * 功能: 模拟访问数据库执行非常耗时间的sql.
     */
    private static Double get() {
        try {
            Thread.sleep(1000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //模拟的数据库结果
        return 9.9D;
    }


}
